package com.example.mq2.mqserver.core;

public class Router {

    /**
     * 检验 routingKey 格式
     * 只允许出现：数字、字母、下划线
     * @param routingKey
     * @return
     */
    public boolean checkRoutingKey(String routingKey) {
        for(int i = 0; i < routingKey.length(); i++) {
            char ch = routingKey.charAt(i);
            if(ch >= 'a' && ch <= 'z') {
                continue;
            }
            if(ch >= 'A' && ch <= 'Z') {
                continue;
            }
            if(ch >= '1' && ch <= '9') {
                continue;
            }
            if(ch == '_' || ch == '.') {
                continue;
            }
            return false;
        }
        return true;
    }

    /**
     * 校验 bindingKey 格式
     * 允许出现：数字、字母、下划线
     * # 表示匹配任意一个或多个字符
     * * 表示匹配一组字符
     * @param bindingKey
     * @return
     */
    public boolean checkBindingKey(String bindingKey) {
       for(int i = 0; i < bindingKey.length(); i++) {
           char ch = bindingKey.charAt(i);
           if(ch >= 'a' && ch <= 'z') {
               continue;
           }
           if(ch >= 'A' && ch <= 'Z') {
               continue;
           }
           if(ch >= '0' && ch <= '9') {
               continue;
           }
           if(ch == '.' || ch == '#' || ch == '_' || ch == '*') {
               continue;
           }
           return false;
       }
       //这里约定：
        // aaa.#.#.ccc 非法
        // aaa.#.*.ccc 非法
        // aaa.*.#.ccc 非法
        // aaa.*.*.ccc 合法
        String[] words = bindingKey.split("\\.");
       for(int i = 0; i < words.length - 1; i++) {
            if(words[i].length() > 1 && (words[i].contains("#") || words[i].contains("*"))) {
                return false;
            }
            if(words[i].charAt(0) == '#' && words[i + 1].charAt(0) == '#') {
                return false;
            }
            if(words[i].charAt(0) == '#' && words[i + 1].charAt(0) == '*') {
                return false;
            }
            if(words[i].charAt(0) == '*' && words[i + 1].charAt(0) == '#') {
                return false;
            }
       }
        return true;
    }

    /**
     * routingKey 和 bindingKey 匹配规则
     * @param routingKey
     * @param bindingKey
     * @return
     */
    public boolean route(String routingKey, String bindingKey) {
        String[] routingKeyTokens = routingKey.split("\\.");
        String[] bindingKeyTokens = bindingKey.split("\\.");
        int routingKeyIndex = 0;
        int bindingKeyIndex = 0;
        while(routingKeyIndex < routingKeyTokens.length &&
                bindingKeyIndex < bindingKeyTokens.length) {
            if(bindingKeyTokens[bindingKeyIndex].charAt(0) == '#' &&
                   bindingKeyIndex + 1 == bindingKeyTokens.length) {
                //r: aaa.bb.ccc
                //b: aaa.#
                return true;
            }
            if(bindingKeyTokens[bindingKeyIndex].charAt(0) == '#' &&
                    bindingKeyIndex + 1 != bindingKeyTokens.length) {
                //r: aaa.bbb.ccc.ddd
                //b: aaa.#.ddd
                //寻找下一个匹配的位置
                bindingKeyIndex++;
                routingKeyIndex = fundNextIndex(routingKeyTokens, routingKeyIndex, bindingKeyTokens[bindingKeyIndex]);
                if(routingKeyIndex == -1) {
                    //没有找到匹配的位置
                    return false;
                }
                bindingKeyIndex++;
                routingKeyIndex++;
                continue;
            }
            if(bindingKeyTokens[bindingKeyIndex].charAt(0) == '*') {
                //r: aaa.bbb.ccc
                //b: aaa.*.ccc
                bindingKeyIndex++;
                routingKeyIndex++;
                continue;
            }
            if(!bindingKeyTokens[bindingKeyIndex].equals(routingKeyTokens[routingKeyIndex])) {
                //剩下最后一种情况就是纯字符串比较
                //r: aaa.bbb.ccc
                //b: aaa.bb.ccc
                return false;
            }
            bindingKeyIndex++;
            routingKeyIndex++;
        }
        return bindingKeyIndex == bindingKeyTokens.length
                && routingKeyIndex == routingKeyTokens.length;
    }

    /**
     * # 后寻找下一个匹配的位置
     * @param routingKeyTokens
     * @param routingKeyIndex
     * @param target
     * @return
     */
    private int fundNextIndex(String[] routingKeyTokens, int routingKeyIndex, String target) {
        for(int i = routingKeyIndex; i < routingKeyTokens.length; i++) {
            if(routingKeyTokens[i].equals(target)) {
                return i;
            }
        }
        return -1;
    }
}
